package cn.ljy.authority.web.controller.backstage;

import cn.ljy.authority.service.BaseService;
import cn.ljy.common.annotation.LimitRequest;
import cn.ljy.common.model.result.ResponseData;
import cn.ljy.common.utils.page.Pagination;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.io.Serializable;


/**
 * @author ljy
 * 基础控制器，用于规范继承类增删改查方法
 * 说明：
 * 1.如果子类在继承时没有重写本类的方法，则本类的方法和方法内的验证都会生效
 * 2.如果子类的方法在继承时重写了本方法，则只需要super调用相应方法就会执行通用函数即可，但是本类的验证会失效，必须在子类重新验证
 * 例如子类重写的删除方法：
 *     @ApiOperation(value = "批量删除指定的多个角色")
 *     @ApiImplicitParam(name = "ids", value = "要删除的id集合", required = true,paramType = "query",example ="[11,12,13]")
 *     @PreAuthorize("hasAuthority('sys:role:del')")
 *     @Override
 *     public ResponseData deletes(Integer[] ids){
 *         return super.deletes(ids);
 *     }
 *
 * @param <T> 操作对象类
 * @param <Q> 操作对象的查询类
 * @param <K> 操作对象类的主键类型
 */
@RestController
@Slf4j
@Validated //加了后@NoNull之类的注解才能生效，如果只是@valid注解则不需要加上
public abstract class BaseBackstageController<T,Q,K> extends BaseController{

    @Autowired
    private BaseService<T,Q> baseService;

    @ApiOperation(value = "查询所有记录列表")
    @LimitRequest
    // 由于本操作不是所有模块都有，一般分页和查询所有记录都是取其一。
    // 所以取消@getmappding，避免因为没写代码被访问到。
    // 子类需要手动添加@GetMapping("/all")
//    @GetMapping("/all")
    protected ResponseData query(Q query){
        return ResponseData.success(baseService.findAll(query));
    }

    @ApiOperation(value = "分页查询记录列表")
    @LimitRequest
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "页码", defaultValue = "1"),
            @ApiImplicitParam(name = "pageSize", value = "每页最大记录数", defaultValue = "20")
    })
    // 由于本操作不是所有模块都有，一般分页和查询所有记录都是取其一。
    // 所以取消@getmappding，避免因为没写代码被访问到。
    // 子类需要手动添加@GetMapping
    @GetMapping
    protected ResponseData query(Integer page, Integer pageSize, Q query){
        Pagination pagination = baseService.findAll(page,pageSize,query);
        return ResponseData.success(pagination);
    }

    @ApiOperation(value = "读取记录")
    @LimitRequest
    @GetMapping("/{id}")
    protected ResponseData get(@PathVariable("id") K id){
        T t=baseService.get((Serializable)id);
        if(t!=null){
            return ResponseData.success(t);
        }else{
            return ResponseData.error("找不到指定记录");
        }

    }

    @ApiOperation(value = "编辑记录")
    @LimitRequest
    @PutMapping
    protected ResponseData edit(@Valid @RequestBody T t){
        baseService.update(t);
        return ResponseData.success(null);
    }

    @ApiOperation(value = "添加记录")
    @LimitRequest
    @PostMapping
    protected ResponseData add(@Valid @RequestBody T t){
        baseService.save(t);
        return ResponseData.success(null);
    }

    // 关于@NotEmpty验证。如果继承的子类重写了本类的函数，则验证效果只在子类生效，也需要添加父类相同的验证效果
    // 如果子类没有写@NotEmpty的验证，则无论本类还是子类都不会有验证效果
    @ApiOperation(value = "批量删除记录")
    @LimitRequest
    @ApiImplicitParam(name = "ids", value = "要删除的id集合", required = true,paramType = "query",example ="[11,12,13]")
    @DeleteMapping
    protected ResponseData deletes(@NotEmpty(message="请选择要移除的记录") K[] ids){
        baseService.delete((Serializable[])ids);
        return ResponseData.success(null);
    }
}
